<?php
/**
 * 通知业务
 *
 * @author peihong <peihong.zhangph@aliyun-inc.com>
 * @copyright ©2003-2103 phpwind.com
 * @license http://www.phpwind.com
 *
 * @version $Id: PwNoticeService.php 3833 2012-01-12 03:32:27Z peihong.zhangph $
 */
class PwNoticeService
{
    /**
     * 发送通知.
     *
     * @param int    $uid
     * @param string $type
     * @param int    $param
     * @param array  $extendParams
     * @param $updateUnRead 是否更新未读数
     */
    public function sendNotice($uid, $type, $param = 0, $extendParams = array(), $updateUnRead = true)
    {
        $action = $this->_getAction($type);
        if (!$action) {
            return new PwError('MESSAGE::notice.type.undefined');
        }

        $typeId = $this->_getTypeId($type);
        // 看是否发通知
        if ($this->_checkPrivate($uid, $typeId) !== true) {
            return false;
        }
        //aggregated notice
        Wind::import('SRV:message.dm.PwMessageNoticesDm');
        $dm = new PwMessageNoticesDm();

        $action->aggregate && $notice = $this->_getNoticesDs()->getNoticeByUid($uid, $typeId, $param);
        $extendParams = $action->formatExtendParams($extendParams, $notice);
        $noticeTitle = $action->buildTitle($param, $extendParams, $notice);

        $dm->setToUid($uid)
            ->setRead(0)
            ->setType($typeId)
            ->setParam($param)
            ->setExtendParams($extendParams)
            ->setTitle($noticeTitle);
        if (!$notice) {
            $noticeId = $this->_getNoticesDs()->addNotice($dm);
        } else {
            $dm->setId($notice['id']);
            $dm->setModifiedTime(Pw::getTime());
            $this->_getNoticesDs()->updateNotice($dm);
            $noticeId = $notice['id'];
        }

        //更新通知未读数
        if ($updateUnRead && (!$notice || $notice['is_read'])) {
            Wind::import('SRV:user.dm.PwUserInfoDm');
            $dm = new PwUserInfoDm($uid);
            $dm->addNotice(1);
            $this->_getUserDs()->editUser($dm, PwUser::FETCH_DATA);
        }

        return true;
    }

    /**
     * 发送一般通知(无类型).
     *
     * @param int    $uid
     * @param string $content
     * @param string $title
     */
    public function sendDefaultNotice($uid, $content, $title = '')
    {
        $extendParams = array('content' => $content, 'title' => $title);

        return $this->sendNotice($uid, 'default', 0, $extendParams);
    }

    /**
     * 按类型统计
     *
     * @param unknown_type $uid
     */
    public function countNoticesByType($uid)
    {
        $list = $this->_getNoticesDs()->countNoticesByType($uid);
        $data = array();
        if (is_array($list)) {
            $typeNames = $this->_getTypeNames();
            $typeIds = array_flip($this->_getTypes());
            foreach ($list as $v) {
                $type = $typeIds[$v['typeid']];
                if (!$type) {
                    continue;
                }
                $data[0]['count'] += $v['num'];
                $data[$v['typeid']] = array(
                    'typename' => $typeNames[$type],
                    'type'     => $type,
                    'count'    => $v['num'],
                );
            }
            $data[0] && $data[0]['typename'] = '全部';
        }

        return $data;
    }

    /**
     * (忽略|取消忽略)一个通知.
     */
    public function ignoreNotice($id, $ignore = 1)
    {
        $id = intval($id);
        $ignore = intval($ignore);
        $ignore = $ignore ? 1 : 0;
        $notice = $this->_getNoticesDs()->getNotice($id);
        if (!$notice) {
            return false;
        } else {
            Wind::import('SRV:message.dm.PwMessageNoticesDm');
            $dm = new PwMessageNoticesDm($id);
            $dm->setIgnore($ignore);
            $this->_getNoticesDs()->updateNotice($dm);
            //ingore to app
            $noticeAction = $this->_getActionByTypeid($notice['typeid']);
            if ($noticeAction && $noticeAction->ignoreNotice) {
                $noticeAction->ignoreNotice($notice, $ignore);
            }

            return true;
        }
    }

    /**
     * @param array $notice
     */
    public function getDetailList($notice)
    {
        if (!is_array($notice)) {
            return null;
        }
        $action = $this->_getActionByTypeid($notice['typeid']);
        if (!$action) {
            return null;
        }

        return $action->getDetailList($notice);
    }

    public function formatNoticeList($noticeList)
    {
        $typeIds = array_flip($this->_getTypes());
        $messageFromUids = array();
        $uid = 0;
        foreach ($noticeList as $k => $v) {
            $v['extend_params'] = @unserialize($v['extend_params']);
            $v['type'] = $typeIds[$v['typeid']];
            if ($v['type'] == 'message') {
                $uid = $v['extend_params']['to_uid'];
                $messageFromUids[$k] = $v['param'];
            }
            $noticeList[$k] = $v;
        }
        //取私信相关信息
        $messageInfos = $this->_getWindid()->getDialogByUsers($uid, $messageFromUids);
        if ($messageInfos) {
            foreach ($messageInfos as $v) {
                $noticeKey = array_search($v['from_uid'], $messageFromUids);
                $extend = array(
                    'title'         => $this->_parseUrl($v['last_message']['content']),
                    'unread_count'  => $v['unread_count'],
                    'message_count' => $v['message_count'],
                );
                $noticeList[$noticeKey]['message_extend_params'] = $extend;
            }
        }

        return $noticeList;
    }

    /**
     * 根据类型ID获取类型名.
     *
     * @param int $typeid
     *
     * @return string
     */
    public function getTypenameByTypeid($typeid)
    {
        $typeNames = $this->_getTypeNames();
        $typeIds = array_flip($this->_getTypes());

        return $typeIds[$typeid];
    }

    /**
     * 根据类型删除通知.
     *
     * @param int    $uid
     * @param string $type
     * @param int    $param
     * @param bool
     */
    public function deleteNoticeByType($uid, $type, $param)
    {
        $typeId = $this->_getTypeId($type);

        return $this->_getNoticesDs()->deleteNoticeByType($uid, $typeId, $param);
    }

    /**
     * 根据uid删除通知.
     *
     * @param int $uid
     * @param bool
     */
    public function deleteNoticeByUid($uid)
    {
        $this->_getNoticesDs()->deleteNoticeByUid($uid);
        Wind::import('SRV:user.dm.PwUserInfoDm');
        $user = Wekit::load('user.PwUser');
        $dm = new PwUserInfoDm($uid);
        $dm->setNoticeCount(0);
        $user->editUser($dm, PwUser::FETCH_DATA);
    }

    /**
     * 根据类型批量删除通知.
     *
     * @param int    $uid
     * @param string $type
     * @param array  $params
     * @param bool
     */
    public function detchDeleteNoticeByType($uid, $type, $params)
    {
        $typeId = $this->_getTypeId($type);

        return $this->_getNoticesDs()->betchDeleteNoticeByType($uid, $typeId, $params);
    }

    /**
     * 根据类型ID设置忽略.
     *
     * @param int $typeId
     * @param int $uid
     *
     * @return bool
     */
    public function setIgnoreNotice($typeId, $uid, $ignore = 1)
    {
        $config = $this->_getMessagesDs()->getMessageConfig($uid);
        $noticeValue = $config['notice_types'] ? unserialize($config['notice_types']) : array();
        $newArray = array($typeId => $typeId);
        if ($ignore) {
            $noticeValue = $noticeValue + $newArray;
        } else {
            $noticeValue = array_diff_key($noticeValue, $newArray);
        }

        return $this->_getMessagesDs()->setMessageConfig($uid, $config['privacy'], serialize($noticeValue));
    }

    /**
     * 获取通知设置忽略类型.
     *
     * @return array
     */
    public function getNoticeTypeSet()
    {
        $privateType = $this->_getNoticePrivateType();
        $types = $this->_getTypeNames();
        $tmpTypes = array();
        foreach ($privateType as $k => $v) {
            if (in_array($k, array_keys($types))) {
                $tmpTypes[$v] = $types[$k];
            }
        }

        return $tmpTypes;
    }

    /**
     * 某个类型是否被忽略.
     *
     * @param int $uid
     * @param int $typeId
     *
     * @return array
     */
    public function isIgnoreNoticeType($uid, $typeId)
    {
        if (!in_array($typeId, $this->_getNoticePrivateType())) {
            return false;
        }
        $config = $this->_getMessagesDs()->getMessageConfig($uid);
        if (!$config['notice_types']) {
            return false;
        }
        $types = unserialize($config['notice_types']);

        return !in_array($typeId, $types) ? false : true;
    }

    /**
     * Enter description here ...
     *
     * @param string $type
     *
     * @return PwNoticeAction
     */
    protected function _getAction($type)
    {
        if (!$type || !in_array($type, array_keys($this->_getTypes()))) {
            return false;
        }
        list($type) = explode('_', $type);
        $actionMethod = sprintf('_get%sAction', ucfirst($type));
        if (!method_exists($this, $actionMethod)) {
            $type = strtolower($type);
            $className = sprintf('PwNotice%s', ucfirst($type));
            $fliePath = 'SRV:message.srv.notice.'.$className;
            Wind::import($fliePath);

            return new $className();
        } else {
            return $this->$actionMethod();
        }
    }

    private function _parseUrl($message)
    {
        // $searcharray = array(
        //     "/\[url=((https?|ftp|gopher|news|telnet|mms|rtsp|thunder|ed2k)?[^\[\s]+?)(\,(1)\/?)?\](.+?)\[\/url\]/eis",
        //     "/\[url\]((https?|ftp|gopher|news|telnet|mms|rtsp|thunder|ed2k)?[^\[\s]+?)\[\/url\]/eis",
        // );
        preg_replace_callback("/\[url\]((https?|ftp|gopher|news|telnet|mms|rtsp|thunder|ed2k)?[^\[\s]+?)\[\/url\]/is", $message, $match);

        return $match[1] ? $match[1] : $message;
    }

    /**
     * Enter description here ...
     *
     * @param int $typeId
     *
     * @return PwNoticeAction
     */
    protected function _getActionByTypeid($typeId)
    {
        $typeId = intval($typeId);
        $types = array_flip($this->_getTypes());

        return $this->_getAction($types[$typeId]);
    }

    private function _getNoticePrivateType()
    {
        return array(
            'medal'  => 4,
            'task'   => 5,
            'credit' => 14,
        );
    }

    private function _getTypes()
    {
        return array(
            'message'        => 1,
            'default'        => 2,
            'threadmanage'   => 3,
            'medal'          => 4,
            'task'           => 5,
            'massmessage'    => 6,
            'report_thread'  => 7,
            'report_post'    => 8,
            'report_message' => 9,
            'threadreply'    => 10,
            'attention'      => 11,
            'remind'         => 12,
            'ban'            => 13,
            'credit'         => 14,
            'postreply'      => 15,
            'report_photo'   => 16,
            'app'            => 99,
        );
    }

    private function _getTypeNames()
    {
        return array(
            'default'        => '通知',
            'message'        => '私信',
            'threadreply'    => '回复提醒',
            'threadmanage'   => '管理提醒',
            'medal'          => '勋章',
            'task'           => '任务',
            'massmessage'    => '群发消息',
            'report_thread'  => '帖子举报',
            'report_post'    => '回复举报',
            'report_message' => '私信举报',
            'attention'      => '关注',
            'remind'         => '@提醒',
            'ban'            => '帐号管理',
            'credit'         => '积分变动',
            'postreply'      => '楼层回复',
            'report_photo'   => '照片举报',
            'app'            => '应用通知',
        );
    }

    /**
     * 检查通知设置权限.
     *
     * @param int $uid
     * @param int $type
     *
     * @return bool
     */
    public function _checkPrivate($uid, $typeId)
    {
        $config = $this->_getMessagesDs()->getMessageConfig($uid);
        if (!$config['notice_types']) {
            return true;
        }
        $noticeValue = unserialize($config['notice_types']);
        $noticeType = array_intersect_key($noticeValue, $this->getNoticeTypeSet());
        if (in_array($typeId, array_keys($noticeType))) {
            return false;
        }

        return true;
    }

    private function _getTypeId($typeName)
    {
        $types = $this->_getTypes();
        if (!is_array($types) || !isset($types[$typeName])) {
            return 0;
        }

        return $types[$typeName];
    }

    private function _getWindid()
    {
        return WindidApi::api('message');
    }

    /**
     * Enter description here ...
     *
     * @return PwMessageNotices
     */
    private function _getNoticesDs()
    {
        return Wekit::load('message.PwMessageNotices');
    }

    /**
     * Enter description here ...
     *
     * @return PwMessageMessages
     */
    private function _getMessagesDs()
    {
        return Wekit::load('message.PwMessageMessages');
    }

    /**
     * Enter description here ...
     *
     * @return PwUser
     */
    private function _getUserDs()
    {
        return Wekit::load('user.PwUser');
    }
}
